#!/usr/bin/env python
# -*- coding: utf-8 -*-
from socket import *
import threading
import datetime
import time
import os
import re
import requests

lock = threading.Lock()

host_list = []         #主机列表
HostSepList=[]          #每个线程分配的主机片。嵌套列表
port_list=[]            #端口清单

def check_ip(ipAddr):
    ip_list=[]
    #格式1：xxx.xxx.xxx.xxx
    #格式2：xxx.xxx.xxx.xxx-yyy
    pattern1 = re.compile(r'^(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})(\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})){3}$')   
    pattern2 = re.compile(r'^(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})(\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})){3}(-\d+)$')  
    if pattern1.match(ipAddr):
        ip_list.append(ipAddr)
        #print(ip_list)
        isIP = True
    elif pattern2.match(ipAddr):
        list1 = ipAddr.split('-')
        list2 = list1[0].split('.')
        i = int(list2[3])
        end  = int(list1[1])
        if end > 254:
            end = 254
        ipstr = ".".join(list2[0:3])+'.'
        while True:
            ip_list.append(ipstr+str(i))
            i += 1
            if i > end:
                break
        #print(ip_list)
        isIP = True
    else:
        isIP = False
    return isIP,ip_list

def read_file(file_path): 
    # 判断文件路径是否存在，如果不存在直接退出，否则读取文件内容
    if not os.path.exists(file_path):
        print('Please confirm correct filepath !')
        exit(0)
    else:
        with open(file_path, 'r') as source:
            for line in source:
                #print(line.rstrip('\r\n').rstrip('\n'))
                AddrStr=line.rstrip('\r\n').rstrip('\n').strip()
                if AddrStr[0] == '#':            #跳过‘#’号开头的注释行
                    continue
                (isIP,ip_list) = check_ip(AddrStr)
                if isIP:
                    host_list.extend(ip_list)
                else: 
                    #域名
                    host_list.append(AddrStr)
    print(host_list)

def separateHost(ThreadCount):    #对host列表进行分片。 给每个线程分一片，即分片数等于线程数
    list_len = len(host_list)
    full_piece_num = list_len % ThreadCount      #满片的个数。注意能够整除的特殊情况。
    full_piece_len = int(list_len/ThreadCount) + 1     #满片的长度（一个满片的host个数）。注意能够整除的特殊情况。
   
    piece_start = 0
    for i in range(full_piece_num):       #分满片的。当能整除时，本循环不执行。
        piece_end = piece_start +  full_piece_len
        HostSepList.append(host_list[piece_start:piece_end])
        piece_start = piece_end
        #print(HostSepList) 

    for i in range(full_piece_num,ThreadCount):   #生成满片长度-1的的片
        piece_end = piece_start + full_piece_len - 1
        HostSepList.append(host_list[piece_start:piece_end])
        piece_start = piece_end
    print(HostSepList)

def run_one_thread(address_list):   #每个线程的运作 参数为文件名称的列表
    ok_f=open(ScanOutputFile,"a+")
    for host in address_list:
        open_port_list = []
        for port in port_list:
            try:
                s = socket(AF_INET,SOCK_STREAM)
                s.settimeout(3)
                s.connect((host,port))
                s.close()
                open_port_list.append(str(port))
            except Exception as e:
                #raise e
                pass
        lock.acquire()
        print("%s %s"%(host,",".join(open_port_list)))
        ok_f.write("%s %s\n" %(host,",".join(open_port_list)))
        lock.release()
    ok_f.close()

#多线程函数
def multithreading(threadCount):
    separateHost(threadCount)#先分离
    for i in range(0,threadCount):
        t=threading.Thread(target=run_one_thread,args=(HostSepList[i],))
        t.start()

if __name__ == '__main__':
    CurTime = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
    ScanOutputFile = 'scan_output_'+CurTime+'.txt'
    ip_list_file="ip.txt"
    port_list=[80,443,8080,8009] 
    
    read_file(ip_list_file)
   # exit()
    thread_num=20
    if len(host_list)<thread_num:
        thread_num=len(host_list)
    print(thread_num)
    multithreading(thread_num)
